package com.jhf.youke.base.domain.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.jhf.youke.base.domain.converter.CompanyConverter;
import com.jhf.youke.base.domain.exception.CompanyException;
import com.jhf.youke.base.domain.gateway.CompanyRepository;
import com.jhf.youke.base.domain.model.Do.CompanyDo;
import com.jhf.youke.base.domain.model.po.CompanyPo;
import com.jhf.youke.base.domain.model.vo.CompanyVo;
import com.jhf.youke.core.ddd.AbstractDomainService;
import com.jhf.youke.core.entity.PageQuery;
import com.jhf.youke.core.entity.Pagination;
import com.jhf.youke.core.utils.CacheUtils;
import com.jhf.youke.core.utils.Constant;
import com.jhf.youke.core.utils.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author  RHJ
 * **/

@Service
public class CompanyService extends AbstractDomainService<CompanyRepository, CompanyDo, CompanyVo> {


    @Resource
    CompanyConverter companyConverter;

    @Override
    public boolean update(CompanyDo entity) {
        CompanyPo companyPo = companyConverter.do2Po(entity);
        companyPo.preUpdate();
        updateParentIds(companyPo, true);
        delCaches(companyPo);
        return repository.update(companyPo);
    }

    @Override
    public boolean updateBatch(List<CompanyDo> doList) {
        List<CompanyPo> poList = companyConverter.do2PoList(doList);
        return repository.updateBatch(poList);
    }

    @Override
    public boolean delete(CompanyDo entity) {
        CompanyPo companyPo = companyConverter.do2Po(entity);
        return repository.delete(companyPo);
    }

    @Override
    public boolean deleteBatch(List<Long> idList) {
        return repository.deleteBatch(idList);
    }

    /**
     * 更新上级ID集合
     * @return CompanyPo
     */
    private CompanyPo updateParentIds(CompanyPo companyPo, Boolean isUpdate) {
        if(companyPo.getParentId() != null && ! Constant.RESPONSE_SUCCESS.equals(StringUtils.chgNull(companyPo.getParentId()))){
            Optional<CompanyPo> parentCompany = repository.findById(companyPo.getParentId());
            parentCompany.orElseThrow(() -> new CompanyException("单位不存在"));
            companyPo.setRootId(parentCompany.get().getRootId());
            companyPo.setParentIds(parentCompany.get().getParentIds() + "," + companyPo.getId());
        }else {
            companyPo.setRootId(companyPo.getId());
            companyPo.setParentIds(companyPo.getId().toString());
        }
        if(isUpdate) {
            Optional<CompanyPo> oldCompany = repository.findById(companyPo.getId());
            oldCompany.orElseThrow(() -> new CompanyException("旧单位不存在"));
            if(!oldCompany.get().getParentId().equals(companyPo.getParentId())){
                //此次更新修改了父类ID，则需要更新此单位的下级单位父类集合
                updateSubParentIds(companyPo);
            }
        }
        return companyPo;
    }

    /**
     * 更新此单位下级单位的父类集合
     */
    private void updateSubParentIds(CompanyPo companyPo) {
        CompanyPo param = new CompanyPo();
        param.setParentId(companyPo.getId());
        List<CompanyPo> subList = repository.findAllMatching(param);
        if(subList.size() == 0){
            return;
        }
        for(CompanyPo item:subList){
            item.setRootId(companyPo.getRootId());
            item.setParentIds(companyPo.getParentIds() + "," + companyPo.getId());
            repository.update(item);
            updateSubParentIds(item);
        }
    }

    @Override
    public boolean insert(CompanyDo entity) {
        CompanyPo companyPo = companyConverter.do2Po(entity);
        companyPo.preInsert();
        updateParentIds(companyPo, false);
        delCaches(companyPo);
        return repository.insert(companyPo);
    }

    private void delCaches(CompanyPo companyPo) {
        String regex = ",";
        for(String id:companyPo.getParentIds().split(regex)){
            String key = "company_ids_" + id;
            CacheUtils.del(key);
        }
    }

    @Override
    public boolean insertBatch(List<CompanyDo> doList) {
        List<CompanyPo> poList = companyConverter.do2PoList(doList);
        CompanyPo.getInsertListId(poList);
        return repository.insertBatch(poList);
    }

    @Override
    public Optional<CompanyVo> findById(Long id) {
        Optional<CompanyPo> companyPo =  repository.findById(id);
        CompanyVo companyVo = companyConverter.po2Vo(companyPo.orElse(new CompanyPo()));
        return Optional.ofNullable(companyVo);
    }

    @Override
    public boolean remove(Long id) {
        Optional<CompanyPo> companyPo =  repository.findById(id);
        companyPo.orElseThrow( () -> new CompanyException("没有单位对象"));
        delCaches(companyPo.get());
        return repository.remove(id);
    }

    @Override
    public boolean removeBatch(List<Long> idList) {
        return repository.removeBatch(idList);
    }

    @Override
    public List<CompanyVo> findAllMatching(CompanyDo entity) {
        CompanyPo companyPo = companyConverter.do2Po(entity);
        List<CompanyPo>companyPoList =  repository.findAllMatching(companyPo);
        return companyConverter.po2VoList(companyPoList);
    }


    @Override
    public Pagination<CompanyVo> selectPage(CompanyDo entity){
        CompanyPo companyPo = companyConverter.do2Po(entity);
        PageQuery<CompanyPo> pageQuery = new PageQuery<>(companyPo,entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<CompanyPo> pagination = repository.selectPage(pageQuery);
        return new Pagination<>(pagination.getPageNum(),pagination.getPageSize(),pagination.getTotalSize(),
                companyConverter.po2VoList(pagination.getList()));
    }

    public List<CompanyVo> companyTree(){
        List<CompanyPo> companyPoList =  repository.findAllMatching(new CompanyPo());
        List<CompanyVo> voList = companyConverter.po2VoList(companyPoList);
        return getTree(voList);
    }

    public List<CompanyVo> getTree(List<CompanyVo> list){
        Multimap<Long, CompanyVo> mulMap = ArrayListMultimap.create();
        List<CompanyVo> menuVoList = new ArrayList<>();
        for(CompanyVo menuVo : list){
            mulMap.put(menuVo.getParentId(), menuVo);
        }
        Collection<CompanyVo> menuVos = mulMap.get(0L);
        menuVos.forEach(menu -> {
            getSubTree(menu, mulMap);
            menuVoList.add(menu);
        });
        return menuVoList;
    }

    public CompanyVo getSubTree(CompanyVo menuVo, Multimap<Long, CompanyVo> mulMap){
        Collection<CompanyVo> menuVos = mulMap.get(menuVo.getId());
        menuVo.setChildren( new  ArrayList<>(menuVos));
        menuVos.forEach(menu ->  getSubTree(menu, mulMap));
        return menuVo;
    }

    /**
     * 根据用户填写的单位ID，找到部门ID以及公司ID
     * @return Map<String, Long>
     */
    public Map<String, Long> getDeptIdAndCompanyId(Long companyId){
        Map<String, Long> data = new HashMap<>(2);
        Optional<CompanyPo> companyPo =  repository.findById(companyId);

        companyPo.orElseThrow(() -> new CompanyException("单位不存在"));

        int deptType = 2;
        if(companyPo.get().getType() == deptType){
            data.put("deptId", companyPo.get().getId());
            data.put("companyId", getCompanyIdByDeptId(companyPo.get()));
        }else{
            data.put("companyId", companyPo.get().getId());
            data.put("deptId", 0L);
        }
        data.put("rootId", companyPo.get().getRootId());
        return data;
    }

    /**
     * 根据部门ID去找公司ID
     * @return Long
     */
    public Long getCompanyIdByDeptId(CompanyPo po){
        if(po.getType() == 1){
            return po.getId();
        }else {
            if(Constant.RESPONSE_SUCCESS.equals(po.getParentId().toString())){
                return null;
            }
            Optional<CompanyPo> companyPo =  repository.findById(po.getParentId());
            companyPo.orElseThrow(() -> new CompanyException("单位不存在"));
            return getCompanyIdByDeptId(companyPo.get());
        }
    }
}

